package com.insight.service;

import com.insight.common.enums.CollectionType;
import com.insight.common.enums.TaskStatus;
import com.insight.entity.CollectionTask;
import com.insight.entity.DataSource;
import com.insight.repository.CollectionTaskRepository;
import com.insight.dto.collection.TaskHealthResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * T068: 采集任务服务实现
 * 负责采集任务的创建、监控、取消等业务逻辑
 *
 * @author Insight Team
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CollectionTaskService {

    private final CollectionTaskRepository collectionTaskRepository;

    /**
     * 创建采集任务
     *
     * @param dataSource     数据源
     * @param collectionType 采集类型
     * @return 创建的任务
     * @throws IllegalArgumentException 如果参数无效
     */
    @Transactional
    public CollectionTask createTask(DataSource dataSource, CollectionType collectionType) {
        log.info("创建采集任务: dataSource={}, collectionType={}", dataSource, collectionType);

        // 参数校验
        if (dataSource == null) {
            throw new IllegalArgumentException("数据源不能为空");
        }
        if (collectionType == null) {
            throw new IllegalArgumentException("采集类型不能为空");
        }

        // 创建任务实例
        CollectionTask task = new CollectionTask();
        task.setDataSource(dataSource);
        task.setCollectionType(collectionType);
        task.setStatus(TaskStatus.PENDING);
        task.setTablesTotal(0);
        task.setTablesCollected(0);

        // 保存到数据库
        CollectionTask savedTask = collectionTaskRepository.save(task);
        log.info("采集任务创建成功: taskId={}, dataSourceId={}, type={}",
                savedTask.getId(), dataSource.getId(), collectionType);

        return savedTask;
    }

    /**
     * 检查数据源是否有正在运行的任务
     *
     * @param dataSource 数据源
     * @return true 如果有正在运行的任务
     */
    public boolean hasRunningTask(DataSource dataSource) {
        long count = collectionTaskRepository.countByDataSourceAndStatus(dataSource, TaskStatus.RUNNING);
        return count > 0;
    }

    /**
     * 根据ID查询任务
     *
     * @param taskId 任务ID
     * @return 任务Optional
     */
    public Optional<CollectionTask> getTaskById(Long taskId) {
        return collectionTaskRepository.findById(taskId);
    }

    /**
     * 根据ID查询任务(控制器层使用)
     *
     * @param taskId 任务ID
     * @return 任务Optional
     */
    public Optional<CollectionTask> findById(Long taskId) {
        return collectionTaskRepository.findById(taskId);
    }

    /**
     * 分页查询所有任务(控制器层使用)
     *
     * @param pageable 分页参数
     * @return 任务分页结果
     */
    public Page<CollectionTask> findAll(Pageable pageable) {
        return collectionTaskRepository.findAll(pageable);
    }

    /**
     * 根据数据源ID分页查询任务
     *
     * @param datasourceId 数据源ID
     * @param pageable     分页参数
     * @return 任务分页结果
     */
    public Page<CollectionTask> findByDataSource(Long datasourceId, Pageable pageable) {
        return collectionTaskRepository.findByDataSourceId(datasourceId, pageable);
    }

    /**
     * 根据状态分页查询任务
     *
     * @param status   任务状态
     * @param pageable 分页参数
     * @return 任务分页结果
     */
    public Page<CollectionTask> findByStatus(TaskStatus status, Pageable pageable) {
        return collectionTaskRepository.findByStatus(status, pageable);
    }

    /**
     * 根据类型分页查询任务
     *
     * @param type     任务类型
     * @param pageable 分页参数
     * @return 任务分页结果
     */
    public Page<CollectionTask> findByType(CollectionType type, Pageable pageable) {
        return collectionTaskRepository.findByCollectionType(type, pageable);
    }

    /**
     * 根据数据源查询所有任务
     *
     * @param dataSource 数据源
     * @return 任务列表
     */
    public List<CollectionTask> getTasksByDataSource(DataSource dataSource) {
        return collectionTaskRepository.findByDataSource(dataSource);
    }

    /**
     * 根据数据源ID查询所有任务
     *
     * @param dataSourceId 数据源ID
     * @return 任务列表
     */
    public List<CollectionTask> getTasksByDataSourceId(Long dataSourceId) {
        return collectionTaskRepository.findByDataSourceId(dataSourceId);
    }

    /**
     * 根据状态查询任务
     *
     * @param status 任务状态
     * @return 任务列表
     */
    public List<CollectionTask> getTasksByStatus(TaskStatus status) {
        return collectionTaskRepository.findByStatus(status);
    }

    /**
     * 分页查询所有任务
     *
     * @param pageable 分页参数
     * @return 任务分页结果
     */
    public Page<CollectionTask> getTasks(Pageable pageable) {
        return collectionTaskRepository.findAll(pageable);
    }

    /**
     * 获取数据源的最新任务
     *
     * @param dataSource 数据源
     * @return 最新任务Optional
     */
    public Optional<CollectionTask> getLatestTask(DataSource dataSource) {
        return collectionTaskRepository.findFirstByDataSourceOrderByCreatedAtDesc(dataSource);
    }

    /**
     * 获取数据源的最新成功任务
     *
     * @param dataSource 数据源
     * @return 最新成功任务Optional
     */
    public Optional<CollectionTask> getLatestSuccessTask(DataSource dataSource) {
        return collectionTaskRepository.findFirstByDataSourceAndStatusOrderByCreatedAtDesc(
                dataSource, TaskStatus.SUCCESS);
    }

    /**
     * 启动任务 - 将状态从PENDING更新为RUNNING
     *
     * @param taskId 任务ID
     * @return 更新后的任务
     * @throws IllegalArgumentException 如果任务不存在
     */
    @Transactional
    public CollectionTask startTask(Long taskId) {
        log.info("启动采集任务: taskId={}", taskId);

        CollectionTask task = collectionTaskRepository.findById(taskId)
                .orElseThrow(() -> new IllegalArgumentException("任务不存在: taskId=" + taskId));

        task.setStatus(TaskStatus.RUNNING);
        task.setStartTime(LocalDateTime.now());

        CollectionTask updatedTask = collectionTaskRepository.save(task);
        log.info("采集任务已启动: taskId={}, startTime={}", taskId, updatedTask.getStartTime());

        return updatedTask;
    }

    /**
     * 更新任务进度
     *
     * @param taskId          任务ID
     * @param tablesTotal     总表数
     * @param tablesCollected 已采集表数
     * @return 更新后的任务
     * @throws IllegalArgumentException 如果任务不存在或参数无效
     */
    @Transactional
    public CollectionTask updateProgress(Long taskId, Integer tablesTotal, Integer tablesCollected) {
        log.debug("更新任务进度: taskId={}, total={}, collected={}", taskId, tablesTotal, tablesCollected);

        // 参数校验
        if (tablesTotal < 0 || tablesCollected < 0) {
            throw new IllegalArgumentException("表数量不能为负数");
        }
        if (tablesCollected > tablesTotal) {
            throw new IllegalArgumentException("已采集数量不能大于总数量");
        }

        CollectionTask task = collectionTaskRepository.findById(taskId)
                .orElseThrow(() -> new IllegalArgumentException("任务不存在: taskId=" + taskId));

        task.setTablesTotal(tablesTotal);
        task.setTablesCollected(tablesCollected);

        CollectionTask updatedTask = collectionTaskRepository.save(task);
        log.debug("任务进度已更新: taskId={}, progress={}/{}", taskId, tablesCollected, tablesTotal);

        return updatedTask;
    }

    /**
     * 更新失败表信息
     *
     * @param taskId           任务ID
     * @param failedTablesJson 失败表列表的JSON字符串
     * @return 更新后的任务
     * @throws IllegalArgumentException 如果任务不存在
     */
    @Transactional
    public CollectionTask updateFailedTables(Long taskId, String failedTablesJson) {
        log.debug("更新失败表信息: taskId={}", taskId);

        CollectionTask task = collectionTaskRepository.findById(taskId)
                .orElseThrow(() -> new IllegalArgumentException("任务不存在: taskId=" + taskId));

        task.setFailedTables(failedTablesJson);

        CollectionTask updatedTask = collectionTaskRepository.save(task);
        log.debug("失败表信息已更新: taskId={}", taskId);

        return updatedTask;
    }

    /**
     * 完成任务 - 更新状态为SUCCESS
     *
     * @param taskId 任务ID
     * @return 更新后的任务
     * @throws IllegalArgumentException 如果任务不存在
     */
    @Transactional
    public CollectionTask completeTask(Long taskId) {
        log.info("完成采集任务: taskId={}", taskId);

        CollectionTask task = collectionTaskRepository.findById(taskId)
                .orElseThrow(() -> new IllegalArgumentException("任务不存在: taskId=" + taskId));

        task.setStatus(TaskStatus.SUCCESS);
        task.setEndTime(LocalDateTime.now());

        CollectionTask updatedTask = collectionTaskRepository.save(task);
        log.info("采集任务已完成: taskId={}, duration={}ms",
                taskId, calculateDuration(task.getStartTime(), task.getEndTime()));

        return updatedTask;
    }

    /**
     * 任务失败 - 更新状态为FAILED并记录错误信息
     *
     * @param taskId       任务ID
     * @param errorMessage 错误信息
     * @return 更新后的任务
     * @throws IllegalArgumentException 如果任务不存在
     */
    @Transactional
    public CollectionTask failTask(Long taskId, String errorMessage) {
        log.error("采集任务失败: taskId={}, error={}", taskId, errorMessage);

        CollectionTask task = collectionTaskRepository.findById(taskId)
                .orElseThrow(() -> new IllegalArgumentException("任务不存在: taskId=" + taskId));

        task.setStatus(TaskStatus.FAILED);
        task.setErrorMessage(errorMessage);
        task.setEndTime(LocalDateTime.now());

        CollectionTask updatedTask = collectionTaskRepository.save(task);
        log.error("采集任务标记为失败: taskId={}", taskId);

        return updatedTask;
    }

    /**
     * 取消任务 - 只能取消PENDING或RUNNING状态的任务
     *
     * @param taskId 任务ID
     * @return 更新后的任务
     * @throws IllegalArgumentException 如果任务不存在
     * @throws IllegalStateException    如果任务状态不允许取消
     */
    @Transactional
    public CollectionTask cancelTask(Long taskId) {
        log.info("取消采集任务: taskId={}", taskId);

        CollectionTask task = collectionTaskRepository.findById(taskId)
                .orElseThrow(() -> new IllegalArgumentException("任务不存在: taskId=" + taskId));

        // 检查任务状态是否可以取消
        if (!task.getStatus().isCancellable()) {
            throw new IllegalStateException("无法取消已完成的任务: taskId=" + taskId + ", status=" + task.getStatus());
        }

        task.setStatus(TaskStatus.CANCELLED);
        task.setEndTime(LocalDateTime.now());

        CollectionTask updatedTask = collectionTaskRepository.save(task);
        log.info("采集任务已取消: taskId={}", taskId);

        return updatedTask;
    }

    /**
     * 检查任务健康状态
     * 识别运行时间过长或卡住的任务
     *
     * @param task 采集任务
     * @return 健康检查响应
     */
    public TaskHealthResponse checkTaskHealth(CollectionTask task) {
        log.debug("检查任务健康状态: taskId={}, status={}", task.getId(), task.getStatus());

        TaskHealthResponse.TaskHealthResponseBuilder responseBuilder = TaskHealthResponse.builder()
                .taskId(task.getId())
                .status(task.getStatus().toString());

        // 如果任务不在运行状态，直接返回健康
        if (task.getStatus() != TaskStatus.RUNNING) {
            return responseBuilder
                    .healthStatus("HEALTHY")
                    .message("任务状态: " + task.getStatus())
                    .recommendCancel(false)
                    .build();
        }

        // 计算运行时长
        Duration runningDuration = Duration.between(task.getStartTime(), LocalDateTime.now());
        long runningMinutes = runningDuration.toMinutes();

        responseBuilder.runningMinutes(runningMinutes);

        // 健康检查逻辑
        if (runningMinutes > 60) {
            // 运行超过60分钟 - 不健康
            return responseBuilder
                    .healthStatus("UNHEALTHY")
                    .message(String.format("任务运行时间过长: %d分钟，建议检查或取消", runningMinutes))
                    .recommendCancel(true)
                    .build();
        } else if (runningMinutes > 30) {
            // 运行超过30分钟 - 警告
            return responseBuilder
                    .healthStatus("WARNING")
                    .message(String.format("任务运行时间较长: %d分钟", runningMinutes))
                    .recommendCancel(false)
                    .build();
        } else {
            // 运行30分钟以内 - 健康
            return responseBuilder
                    .healthStatus("HEALTHY")
                    .message(String.format("任务正常运行: %d分钟", runningMinutes))
                    .recommendCancel(false)
                    .build();
        }
    }

    /**
     * 删除指定数据源的所有任务
     *
     * @param dataSource 数据源
     */
    @Transactional
    public void deleteTasksByDataSource(DataSource dataSource) {
        log.info("删除数据源的所有任务: dataSourceId={}", dataSource.getId());
        collectionTaskRepository.deleteByDataSource(dataSource);
        log.info("数据源任务已删除: dataSourceId={}", dataSource.getId());
    }

    /**
     * 删除指定数据源ID的所有任务
     *
     * @param dataSourceId 数据源ID
     */
    @Transactional
    public void deleteTasksByDataSourceId(Long dataSourceId) {
        log.info("删除数据源的所有任务: dataSourceId={}", dataSourceId);
        collectionTaskRepository.deleteByDataSourceId(dataSourceId);
        log.info("数据源任务已删除: dataSourceId={}", dataSourceId);
    }

    /**
     * 统计指定状态的任务数量
     *
     * @param status 任务状态
     * @return 任务数量
     */
    public long countByStatus(TaskStatus status) {
        return collectionTaskRepository.countByStatus(status);
    }

    /**
     * 统计数据源指定状态的任务数量
     *
     * @param dataSource 数据源
     * @param status     任务状态
     * @return 任务数量
     */
    public long countByDataSourceAndStatus(DataSource dataSource, TaskStatus status) {
        return collectionTaskRepository.countByDataSourceAndStatus(dataSource, status);
    }

    /**
     * 计算任务执行时长(毫秒)
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 时长(毫秒),如果时间为null则返回0
     */
    private long calculateDuration(LocalDateTime startTime, LocalDateTime endTime) {
        if (startTime == null || endTime == null) {
            return 0;
        }
        return java.time.Duration.between(startTime, endTime).toMillis();
    }
}
